// ES6 ES2015
// https://promisesaplus.com/

const PROMISE_STATUS_PENDING = "pending";
const PROMISE_STATUS_FULFILLED = "fulfilled";
const PROMISE_STATUS_REJECTED = "rejected";

function execFunctionWithCatchError(exeFn, value, resolve, reject) {
  try {
    const ret = exeFn(value);
    resolve(ret);
  } catch (err) {
    // 捕获异常
    reject(err);
  }
}

class XJHPromise {
  constructor(executor) {
    // 状态
    this.status = PROMISE_STATUS_PENDING;
    // 保存成功的值
    this.value = undefined;
    // 保存错误数据
    this.reason = undefined;
    this.onFulfilledFns = [];
    this.onRejectedFns = [];

    // 代替执行
    const resolve = (value) => {
      if (this.status === PROMISE_STATUS_PENDING) {
        queueMicrotask(() => {
          if (this.status !== PROMISE_STATUS_PENDING) return;
          this.status = PROMISE_STATUS_FULFILLED;
          this.value = value;
          this.onFulfilledFns.forEach((item) => {
            item(this.value);
          });
        });
        // console.log("resolve 别调用");
      }
    };
    const reject = (reason) => {
      if (this.status === PROMISE_STATUS_PENDING) {
        // 微任务队列
        queueMicrotask(() => {
          // 前面的优化，后续的就不用执行了
          if (this.status !== PROMISE_STATUS_PENDING) return;
          this.status = PROMISE_STATUS_REJECTED;
          this.reason = reason;
          // console.log("reject 别调用");
          this.onRejectedFns.forEach((item) => {
            item(this.reason);
          });
        });
      }
    };
    executor(resolve, reject);
  }

  // on 表示在发生某种的时候执行这个函数
  then(onFulfilled, onRejected) {
    // 如果 我不是一次性传入两个值,就是用这样的方式来解决问题
    onRejected =
      onRejected ||
      ((err) => {
        throw err;
      });
    // 如果只是一个返回值这样, 会走这里
    onFulfilled = onFulfilled || ((value) => value);

    // then 链式调用处理
    return new XJHPromise((resolve, reject) => {
      // 如果后续还有一些 宏任务重新调用的使用， 如果状态确定就可以直接调用了
      if (
        this.status == PROMISE_STATUS_FULFILLED &&
        typeof onFulfilled === "function"
      ) {
        // 函数抽取上面的代码
        execFunctionWithCatchError(onFulfilled, this.value, resolve, reject);
      }

      if (
        this.status == PROMISE_STATUS_REJECTED &&
        typeof onRejected === "function"
      ) {
        // 这里的处理，就和我想要的效果有关系了，我前面的 有catch 也能执行我的then
        execFunctionWithCatchError(onRejected, this.reason, resolve, reject);
      }

      if (this.status == PROMISE_STATUS_PENDING) {
        // 上面做了判断, 这里会有一点点的多余
        if (typeof onFulfilled === "function") {
          this.onFulfilledFns.push(() => {
            // just fn
            execFunctionWithCatchError(
              onFulfilled,
              this.value,
              resolve,
              reject
            );
          });
        }
        if (typeof onRejected === "function") {
          // 可以用可以看出来, 函数上下文只和他定义的地方有关系
          this.onRejectedFns.push(() => {
            execFunctionWithCatchError(
              onRejected,
              this.reason,
              resolve,
              reject
            );
          });
        }
      }
    });
  }

  catch(onRejected) {
    this.then(undefined, onRejected);
  }

  // 无论什么时候都执行一次
  finally(onFinally) {
    this.then(
      () => {
        onFinally();
      },
      () => {
        onFinally();
      }
    );
  }

  static resolve(value) {
    return new XJHPromise((resolve) => resolve(value));
  }
  static reject(reason) {
    return new XJHPromise((resolve, reject) => reject(reason));
  }

  // 全部执行成功才能返回成功, 不然就是失败
  static all(promises) {
    return new XJHPromise((resolve, reject) => {
      const values = [];
      promises.forEach((promise) => {
        promise.then(
          (res) => {
            values.push(res);
            if (values.length == promises.length) {
              // 返回的就是我的这个数组 没有任何的问题
              resolve(values);
            }
          },
          (err) => {
            reject(err);
          }
        );
      });
    });
  }

  // 将所有的promise 全部执行完毕, 最后用来进行统一处理
  static allSettled(promises) {
    return new XJHPromise((resolve) => {
      const results = [];
      promises.forEach((promise) => {
        promise.then(
          (res) => {
            results.push({ status: PROMISE_STATUS_FULFILLED, value: res });
            if (results.length === promises.length) {
              resolve(results);
            }
          },
          (err) => {
            results.push({ status: PROMISE_STATUS_REJECTED, value: err });
            if (results.length == promises.length) {
              resolve(results);
            }
          }
        );
      });
    });
  }

  // 所有的都是一起执行, 错误和成功都是一样的, 有一个调用就执行
  static race(promises) {
    return new XJHPromise((resolve, reject) => {
      promises.forEach((promise) => {
        // 这个细节, 还是扯到了函数的调用问题
        promise.then(resolve, reject);
      });
    });
  }

  // 全是错误的就会执行错误, 有一个正确的就执行正确的
  static any(promises) {
    return new XJHPromise((resolve, reject) => {
      let reasons = [];
      promises.forEach((promise) => {
        // 这个细节, 还是扯到了函数的调用问题
        promise.then(resolve, (err) => {
          reasons.push(err);
          if (reason.length === promises.length) {
            reject("err");
          }
        });
      });
    });
  }
}

const promise = new XJHPromise((resolve, reject) => {
  resolve("111");
  // reject("111");
});
